<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <meta name="nodejs.org:node-version" content="v12.22.7">
  <title>C++ Embedder API | Node.js v12.22.7 Documentation</title>
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700,400italic&display=fallback">
  <link rel="stylesheet" href="assets/style.css">
  <link rel="stylesheet" href="assets/hljs.css">
  <link rel="canonical" href="https://nodejs.org/api/embedding.html">
</head>
<body class="alt apidoc" id="api-section-embedding">
  <div id="content" class="clearfix">
    <div id="column2" class="interior">
      <div id="intro" class="interior">
        <a href="/" title="Go back to the home page">
          Node.js
        </a>
      </div>
      <ul>
<li><a href="documentation.html" class="nav-documentation">About this documentation</a></li>
<li><a href="synopsis.html" class="nav-synopsis">Usage and example</a></li>
</ul>
<hr class="line">
<ul>
<li><a href="assert.html" class="nav-assert">Assertion testing</a></li>
<li><a href="async_hooks.html" class="nav-async_hooks">Async hooks</a></li>
<li><a href="buffer.html" class="nav-buffer">Buffer</a></li>
<li><a href="addons.html" class="nav-addons">C++ Addons</a></li>
<li><a href="n-api.html" class="nav-n-api">C/C++ Addons with N-API</a></li>
<li><a href="embedding.html" class="nav-embedding active">C++ Embedder API</a></li>
<li><a href="child_process.html" class="nav-child_process">Child Processes</a></li>
<li><a href="cluster.html" class="nav-cluster">Cluster</a></li>
<li><a href="cli.html" class="nav-cli">Command line options</a></li>
<li><a href="console.html" class="nav-console">Console</a></li>
<li><a href="crypto.html" class="nav-crypto">Crypto</a></li>
<li><a href="debugger.html" class="nav-debugger">Debugger</a></li>
<li><a href="deprecations.html" class="nav-deprecations">Deprecated APIs</a></li>
<li><a href="dns.html" class="nav-dns">DNS</a></li>
<li><a href="domain.html" class="nav-domain">Domain</a></li>
<li><a href="errors.html" class="nav-errors">Errors</a></li>
<li><a href="events.html" class="nav-events">Events</a></li>
<li><a href="fs.html" class="nav-fs">File system</a></li>
<li><a href="globals.html" class="nav-globals">Globals</a></li>
<li><a href="http.html" class="nav-http">HTTP</a></li>
<li><a href="http2.html" class="nav-http2">HTTP/2</a></li>
<li><a href="https.html" class="nav-https">HTTPS</a></li>
<li><a href="inspector.html" class="nav-inspector">Inspector</a></li>
<li><a href="intl.html" class="nav-intl">Internationalization</a></li>
<li><a href="modules.html" class="nav-modules">Modules: CommonJS modules</a></li>
<li><a href="esm.html" class="nav-esm">Modules: ECMAScript modules</a></li>
<li><a href="module.html" class="nav-module">Modules: <code>module</code> API</a></li>
<li><a href="packages.html" class="nav-packages">Modules: Packages</a></li>
<li><a href="net.html" class="nav-net">Net</a></li>
<li><a href="os.html" class="nav-os">OS</a></li>
<li><a href="path.html" class="nav-path">Path</a></li>
<li><a href="perf_hooks.html" class="nav-perf_hooks">Performance hooks</a></li>
<li><a href="policy.html" class="nav-policy">Policies</a></li>
<li><a href="process.html" class="nav-process">Process</a></li>
<li><a href="punycode.html" class="nav-punycode">Punycode</a></li>
<li><a href="querystring.html" class="nav-querystring">Query strings</a></li>
<li><a href="readline.html" class="nav-readline">Readline</a></li>
<li><a href="repl.html" class="nav-repl">REPL</a></li>
<li><a href="report.html" class="nav-report">Report</a></li>
<li><a href="stream.html" class="nav-stream">Stream</a></li>
<li><a href="string_decoder.html" class="nav-string_decoder">String decoder</a></li>
<li><a href="timers.html" class="nav-timers">Timers</a></li>
<li><a href="tls.html" class="nav-tls">TLS/SSL</a></li>
<li><a href="tracing.html" class="nav-tracing">Trace events</a></li>
<li><a href="tty.html" class="nav-tty">TTY</a></li>
<li><a href="dgram.html" class="nav-dgram">UDP/datagram</a></li>
<li><a href="url.html" class="nav-url">URL</a></li>
<li><a href="util.html" class="nav-util">Utilities</a></li>
<li><a href="v8.html" class="nav-v8">V8</a></li>
<li><a href="vm.html" class="nav-vm">VM</a></li>
<li><a href="wasi.html" class="nav-wasi">WASI</a></li>
<li><a href="worker_threads.html" class="nav-worker_threads">Worker threads</a></li>
<li><a href="zlib.html" class="nav-zlib">Zlib</a></li>
</ul>
<hr class="line">
<ul>
<li><a href="https://github.com/nodejs/node" class="nav-https-github-com-nodejs-node">Code repository and issue tracker</a></li>
</ul>
    </div>

    <div id="column1" data-id="embedding" class="interior">
      <header>
        <h1>Node.js v12.22.7 Documentation</h1>
        <div id="gtoc">
          <ul>
            <li>
              <a href="index.html">Index</a>
            </li>
            <li>
              <a href="all.html">View on single page</a>
            </li>
            <li>
              <a href="embedding.json">View as JSON</a>
            </li>
            
    <li class="version-picker">
      <a href="#">View another version <span>&#x25bc;</span></a>
      <ol class="version-picker"><li><a href="https://nodejs.org/docs/latest-v16.x/api/embedding.html">16.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v15.x/api/embedding.html">15.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v14.x/api/embedding.html">14.x <b>LTS</b></a></li>
<li><a href="https://nodejs.org/docs/latest-v13.x/api/embedding.html">13.x</a></li>
<li><a href="https://nodejs.org/docs/latest-v12.x/api/embedding.html">12.x <b>LTS</b></a></li></ol>
    </li>
  
            <li class="edit_on_github"><a href="https://github.com/nodejs/node/edit/master/doc/api/embedding.md"><span class="github_icon"><svg height="16" width="16" viewBox="0 0 16.1 16.1" fill="currentColor"><path d="M8 0a8 8 0 0 0-2.5 15.6c.4 0 .5-.2.5-.4v-1.5c-2 .4-2.5-.5-2.7-1 0-.1-.5-.9-.8-1-.3-.2-.7-.6 0-.6.6 0 1 .6 1.2.8.7 1.2 1.9 1 2.4.7 0-.5.2-.9.5-1-1.8-.3-3.7-1-3.7-4 0-.9.3-1.6.8-2.2 0-.2-.3-1 .1-2 0 0 .7-.3 2.2.7a7.4 7.4 0 0 1 4 0c1.5-1 2.2-.8 2.2-.8.5 1.1.2 2 .1 2.1.5.6.8 1.3.8 2.2 0 3-1.9 3.7-3.6 4 .3.2.5.7.5 1.4v2.2c0 .2.1.5.5.4A8 8 0 0 0 16 8a8 8 0 0 0-8-8z"/></svg></span>Edit on GitHub</a></li>
          </ul>
        </div>
        <hr>
      </header>

      <div id="toc">
        <h2>Table of Contents</h2>
        <ul>
<li><a href="#embedding_c_embedder_api">C++ Embedder API</a>
<ul>
<li><a href="#embedding_example_embedding_application">Example embedding application</a>
<ul>
<li><a href="#embedding_setting_up_per_process_state">Setting up per-process state</a></li>
<li><a href="#embedding_per_instance_state">Per-instance state</a></li>
</ul>
</li>
</ul>
</li>
</ul>
      </div>

      <div id="apicontent">
        <h1>C++ Embedder API<span><a class="mark" href="#embedding_c_embedder_api" id="embedding_c_embedder_api">#</a></span></h1>

<p>Node.js provides a number of C++ APIs that can be used to execute JavaScript
in a Node.js environment from other C++ software.</p>
<p>The documentation for these APIs can be found in <a href="https://github.com/nodejs/node/blob/master/src/node.h">src/node.h</a> in the Node.js
source tree. In addition to the APIs exposed by Node.js, some required concepts
are provided by the V8 embedder API.</p>
<p>Because using Node.js as an embedded library is different from writing code
that is executed by Node.js, breaking changes do not follow typical Node.js
<a href="deprecations.html">deprecation policy</a> and may occur on each semver-major release without prior
warning.</p>
<h2>Example embedding application<span><a class="mark" href="#embedding_example_embedding_application" id="embedding_example_embedding_application">#</a></span></h2>
<p>The following sections will provide an overview over how to use these APIs
to create an application from scratch that will perform the equivalent of
<code>node -e &#x3C;code></code>, i.e. that will take a piece of JavaScript and run it in
a Node.js-specific environment.</p>
<p>The full code can be found <a href="https://github.com/nodejs/node/blob/master/test/embedding/embedtest.cc">in the Node.js source tree</a>.</p>
<h3>Setting up per-process state<span><a class="mark" href="#embedding_setting_up_per_process_state" id="embedding_setting_up_per_process_state">#</a></span></h3>
<p>Node.js requires some per-process state management in order to run:</p>
<ul>
<li>Arguments parsing for Node.js <a href="cli.html">CLI options</a>,</li>
<li>V8 per-process requirements, such as a <code>v8::Platform</code> instance.</li>
</ul>
<p>The following example shows how these can be set up. Some class names are from
the <code>node</code> and <code>v8</code> C++ namespaces, respectively.</p>
<pre><code class="language-cpp"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span>** argv)</span> </span>{
  argv = uv_setup_args(argc, argv);
  <span class="hljs-function"><span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&#x3C;<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>> <span class="hljs-title">args</span><span class="hljs-params">(argv, argv + argc)</span></span>;
  <span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&#x3C;<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>> exec_args;
  <span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span>&#x3C;<span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>> errors;
  <span class="hljs-comment">// Parse Node.js CLI options, and print any errors that have occurred while</span>
  <span class="hljs-comment">// trying to parse them.</span>
  <span class="hljs-keyword">int</span> exit_code = node::InitializeNodeWithArgs(&#x26;args, &#x26;exec_args, &#x26;errors);
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-built_in">std</span>::<span class="hljs-built_in">string</span>&#x26; error : errors)
    <span class="hljs-built_in">fprintf</span>(<span class="hljs-built_in">stderr</span>, <span class="hljs-string">"%s: %s\n"</span>, args[<span class="hljs-number">0</span>].c_str(), error.c_str());
  <span class="hljs-keyword">if</span> (exit_code != <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">return</span> exit_code;
  }

  <span class="hljs-comment">// Create a v8::Platform instance. `MultiIsolatePlatform::Create()` is a way</span>
  <span class="hljs-comment">// to create a v8::Platform instance that Node.js can use when creating</span>
  <span class="hljs-comment">// Worker threads. When no `MultiIsolatePlatform` instance is present,</span>
  <span class="hljs-comment">// Worker threads are disabled.</span>
  <span class="hljs-built_in">std</span>::<span class="hljs-built_in">unique_ptr</span>&#x3C;MultiIsolatePlatform> platform =
      MultiIsolatePlatform::Create(<span class="hljs-number">4</span>);
  V8::InitializePlatform(platform.get());
  V8::Initialize();

  <span class="hljs-comment">// See below for the contents of this function.</span>
  <span class="hljs-keyword">int</span> ret = RunNodeInstance(platform.get(), args, exec_args);

  V8::Dispose();
  V8::ShutdownPlatform();
  <span class="hljs-keyword">return</span> ret;
}</code></pre>
<h3>Per-instance state<span><a class="mark" href="#embedding_per_instance_state" id="embedding_per_instance_state">#</a></span></h3>
<p>Node.js has a concept of a “Node.js instance”, that is commonly being referred
to as <code>node::Environment</code>. Each <code>node::Environment</code> is associated with:</p>
<ul>
<li>Exactly one <code>v8::Isolate</code>, i.e. one JS Engine instance,</li>
<li>Exactly one <code>uv_loop_t</code>, i.e. one event loop, and</li>
<li>A number of <code>v8::Context</code>s, but exactly one main <code>v8::Context</code>.</li>
<li>One <code>node::IsolateData</code> instance that contains information that could be
shared by multiple <code>node::Environment</code>s that use the same <code>v8::Isolate</code>.
Currently, no testing if performed for this scenario.</li>
</ul>
<p>In order to set up a <code>v8::Isolate</code>, an <code>v8::ArrayBuffer::Allocator</code> needs
to be provided. One possible choice is the default Node.js allocator, which
can be created through <code>node::ArrayBufferAllocator::Create()</code>. Using the Node.js
allocator allows minor performance optimizations when addons use the Node.js
C++ <code>Buffer</code> API, and is required in order to track <code>ArrayBuffer</code> memory in
<a href="process.html#process_process_memoryusage"><code>process.memoryUsage()</code></a>.</p>
<p>Additionally, each <code>v8::Isolate</code> that is used for a Node.js instance needs to
be registered and unregistered with the <code>MultiIsolatePlatform</code> instance, if one
is being used, in order for the platform to know which event loop to use
for tasks scheduled by the <code>v8::Isolate</code>.</p>
<p>The <code>node::NewIsolate()</code> helper function creates a <code>v8::Isolate</code>,
sets it up with some Node.js-specific hooks (e.g. the Node.js error handler),
and registers it with the platform automatically.</p>
<pre><code class="language-cpp">int RunNodeInstance(MultiIsolatePlatform* platform,
                    const std::vector&#x3C;std::string>&#x26; args,
                    const std::vector&#x3C;std::string>&#x26; exec_args) {
  int exit_code = 0;
  // Set up a libuv event loop.
  uv_loop_t loop;
  int ret = uv_loop_init(&#x26;loop);
  if (ret != 0) {
    fprintf(stderr, "%s: Failed to initialize loop: %s\n",
            args[0].c_str(),
            uv_err_name(ret));
    return 1;
  }

  std::shared_ptr&#x3C;ArrayBufferAllocator> allocator =
      ArrayBufferAllocator::Create();

  Isolate* isolate = NewIsolate(allocator, &#x26;loop, platform);
  if (isolate == nullptr) {
    fprintf(stderr, "%s: Failed to initialize V8 Isolate\n", args[0].c_str());
    return 1;
  }

  {
    Locker locker(isolate);
    Isolate::Scope isolate_scope(isolate);

    // Create a node::IsolateData instance that will later be released using
    // node::FreeIsolateData().
    std::unique_ptr&#x3C;IsolateData, decltype(&#x26;node::FreeIsolateData)> isolate_data(
        node::CreateIsolateData(isolate, &#x26;loop, platform, allocator.get()),
        node::FreeIsolateData);

    // Set up a new v8::Context.
    HandleScope handle_scope(isolate);
    Local&#x3C;Context> context = node::NewContext(isolate);
    if (context.IsEmpty()) {
      fprintf(stderr, "%s: Failed to initialize V8 Context\n", args[0].c_str());
      return 1;
    }

    // The v8::Context needs to be entered when node::CreateEnvironment() and
    // node::LoadEnvironment() are being called.
    Context::Scope context_scope(context);

    // Create a node::Environment instance that will later be released using
    // node::FreeEnvironment().
    std::unique_ptr&#x3C;Environment, decltype(&#x26;node::FreeEnvironment)> env(
        node::CreateEnvironment(isolate_data.get(), context, args, exec_args),
        node::FreeEnvironment);

    // Set up the Node.js instance for execution, and run code inside of it.
    // There is also a variant that takes a callback and provides it with
    // the `require` and `process` objects, so that it can manually compile
    // and run scripts as needed.
    // The `require` function inside this script does *not* access the file
    // system, and can only load built-in Node.js modules.
    // `module.createRequire()` is being used to create one that is able to
    // load files from the disk, and uses the standard CommonJS file loader
    // instead of the internal-only `require` function.
    MaybeLocal&#x3C;Value> loadenv_ret = node::LoadEnvironment(
        env.get(),
        "const publicRequire ="
        "  require('module').createRequire(process.cwd() + '/');"
        "globalThis.require = publicRequire;"
        "require('vm').runInThisContext(process.argv[1]);");

    if (loadenv_ret.IsEmpty())  // There has been a JS exception.
      return 1;

    {
      // SealHandleScope protects against handle leaks from callbacks.
      SealHandleScope seal(isolate);
      bool more;
      do {
        uv_run(&#x26;loop, UV_RUN_DEFAULT);

        // V8 tasks on background threads may end up scheduling new tasks in the
        // foreground, which in turn can keep the event loop going. For example,
        // WebAssembly.compile() may do so.
        platform->DrainTasks(isolate);

        // If there are new tasks, continue.
        more = uv_loop_alive(&#x26;loop);
        if (more) continue;

        // node::EmitBeforeExit() is used to emit the 'beforeExit' event on
        // the `process` object.
        node::EmitBeforeExit(env.get());

        // 'beforeExit' can also schedule new work that keeps the event loop
        // running.
        more = uv_loop_alive(&#x26;loop);
      } while (more == true);
    }

    // node::EmitExit() returns the current exit code.
    exit_code = node::EmitExit(env.get());

    // node::Stop() can be used to explicitly stop the event loop and keep
    // further JavaScript from running. It can be called from any thread,
    // and will act like worker.terminate() if called from another thread.
    node::Stop(env.get());
  }

  // Unregister the Isolate with the platform and add a listener that is called
  // when the Platform is done cleaning up any state it had associated with
  // the Isolate.
  bool platform_finished = false;
  platform->AddIsolateFinishedCallback(isolate, [](void* data) {
    *static_cast&#x3C;bool*>(data) = true;
  }, &#x26;platform_finished);
  platform->UnregisterIsolate(isolate);
  isolate->Dispose();

  // Wait until the platform has cleaned up all relevant resources.
  while (!platform_finished)
    uv_run(&#x26;loop, UV_RUN_ONCE);
  int err = uv_loop_close(&#x26;loop);
  assert(err == 0);

  return exit_code;
}</code></pre>
        <!-- API END -->
      </div>
    </div>
  </div>
</body>
</html>
